package com.winchain.chainbill.bill.biz.receive.cmd;

import com.shell.bee.acct.transaction.po.AcctTxRec;
import com.shell.bee.base.utils.DateUtil;
import com.shell.bee.base.utils.SystemUtil;
import com.shell.framework.command.CallbackContext;
import com.shell.framework.command.CommandContext;
import com.shell.framework.command.ICallback;
import com.shell.framework.command.ICommand;
import com.shell.framework.utils.SysDateUtil;
import com.winchain.chainbill.bill.base.po.CbDfrl;
import com.winchain.chainbill.bill.base.po.CbInsAcr;
import com.winchain.chainbill.bill.base.po.CbRec;
import com.winchain.chainbill.bill.base.po.CbXfe;
import com.winchain.chainbill.bill.base.service.CbDfrlService;
import com.winchain.chainbill.bill.base.service.CbInsAcrService;
import com.winchain.chainbill.bill.base.service.CbXfeService;
import com.winchain.chainbill.bill.biz.Bill;
import java.math.BigDecimal;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class BillRcvDfrlCmd<T> implements ICommand<Bill<T>>, ICallback<Bill<T>, AcctTxRec> {
	@Autowired
	private CbXfeService cbXfeService;
	@Autowired
	private CbDfrlService cbDfrlService;
	@Autowired
	private CbInsAcrService cbInsAcrService;

	public boolean execute(CommandContext<Bill<T>> context) throws Exception {
		CbRec cbRecord = ((Bill) context.getSource()).getRec();

		CbDfrl cbDfrl = getcbDfrl(cbRecord.getBillId());
		if (cbDfrl == null) {
			return false;
		}
		Object bizType = context.getValue("bizType");
		if ("cb_rcv".equals(bizType)) {
			cbRecord.setExpDate(cbDfrl.getPreExpDate());
		} else if ("cb_rc_aprv".equals(bizType)) {
			cbDfrl.setDfrlState("1");
			saveCbInsAcr(cbRecord, cbDfrl);
		} else if ("cb_xfe_rev".equals(bizType)) {
			cbRecord.setExpDate(cbDfrl.getExpDate());
		}
		this.cbDfrlService.saveOrUpdate(cbDfrl);

		return false;
	}

	public boolean callback(CallbackContext<Bill<T>, AcctTxRec> context) throws Exception {
		execute(context);
		return false;
	}

	private CbDfrl getcbDfrl(String billId) {
		CbXfe cbXfe = new CbXfe();
		cbXfe.setBillId(billId);
		cbXfe.setXfeState("1");

		cbXfe = (CbXfe) this.cbXfeService.selectOne(cbXfe);
		if (cbXfe == null) {
			return null;
		}
		String xfeId = cbXfe.getXfeId();

		CbDfrl cbDfrl = new CbDfrl();
		cbDfrl.setBillId(billId);
		cbDfrl.setXfeId(xfeId);

		cbDfrl = (CbDfrl) this.cbDfrlService.selectOne(cbDfrl);

		return cbDfrl;
	}

	private void saveCbInsAcr(CbRec cbRecord, CbDfrl cbDfrl) {
		BigDecimal billAmt = cbRecord.getBillAmt();
		CbInsAcr cbInsAcr = new CbInsAcr();
		cbInsAcr.setAcrId(SystemUtil.getUUID());
		cbInsAcr.setBizId(cbDfrl.getXfeId());
		String preExpDate = cbDfrl.getPreExpDate();
		cbInsAcr.setStartDate(preExpDate);
		String expDateStr = cbDfrl.getExpDate();

		String endDateStr = DateUtil.nextOneDay(cbDfrl.getPreExpDate(), 20, "yyyyMMdd");
		if (SysDateUtil.compare(endDateStr, expDateStr) >= 0) {
			endDateStr = expDateStr;
		}
		cbInsAcr.setEndDate(endDateStr);
		cbInsAcr.setAcrMonth(endDateStr.substring(0, 6));
		cbInsAcr.setAcrInsType("2");
		int days = DateUtil.getDaysBetween(preExpDate, endDateStr, "yyyyMMdd").intValue() + 1;
		if (isCurrentMonthDfrl(preExpDate, expDateStr)) {
			days -= 1;
		}
		BigDecimal dfrRate = cbDfrl.getDfrRate();
		BigDecimal curIns = billAmt.multiply(new BigDecimal(days)).multiply(dfrRate.multiply(new BigDecimal("0.01")))
				.divide(new BigDecimal(360), 2, 4);
		cbInsAcr.setCurIns(curIns);
		cbInsAcr.setEarlyIns(new BigDecimal(0));
		cbInsAcr.setTotIns(curIns);
		cbInsAcr.setCreateTime(SysDateUtil.getSystemDateTime());
		this.cbInsAcrService.save(cbInsAcr);
	}

	private boolean isCurrentMonthDfrl(String preExpDate, String expDate) {
		String preMonth = preExpDate.substring(0, 6);
		String expMonth = expDate.substring(0, 6);
		if ((preMonth.equals(expMonth)) && ((SysDateUtil.compare(preExpDate, preMonth + "20") >= 0)
				|| (SysDateUtil.compare(expDate, expMonth + "20") <= 0))) {
			return true;
		}
		return false;
	}
}
